#include <iostream>
#include <cassert>
#include <string>

class Any{
    private:
        class holder{
            public:
                virtual ~holder() {}
                virtual const std::type_info &type() = 0;
                virtual holder *clone() = 0;
        };
        template<class T>
        class placeholder : public holder{
            public:
                placeholder(const T &val): _val(val) {}
                // 获取子类对象保存的数据类型
                virtual const std::type_info &type() { return typeid(T); }
                // 根据当前子类保存的数据，克隆一份新的子类对象
                virtual holder *clone() { return new placeholder(_val); }
            public:
                T _val;
        };
        holder *_content;
    public:
        Any(): _content(nullptr) {}
        template<class T>
        Any(const T& val): _content(new placeholder<T>(val)) {}
        Any(const Any& other): _content(other._content ? other._content->clone() : nullptr) {}
        ~Any() { delete _content; }
        
        Any &swap(Any& other)
        {
            std::swap(_content, other._content);
            return *this;
        }
        template<class T>
        T *get()        // 返回当前保存变量的指针
        {
            // 保存的数据类型，必须和要获取的数据类型一直
            assert(_content->type() == typeid(T));
            return &((placeholder<T>*)_content)->_val;
        }
        template<class T>
        Any &operator=(const T &val)       // 赋值运算符重载
        {
            Any(val).swap(*this);
            return *this;
        }
        Any &operator=(const Any &other)
        {
            Any(other).swap(*this);
            return *this;
        }
};

class Test
{
    public:
        Test() { std::cout << "构造" << std::endl; }
        Test(const Test &t) { std::cout << "拷贝" << std::endl; }
        ~Test() { std::cout << "析构" << std::endl; }
};

int main()
{

    {
        Any a;
        Test t;
        a = t;
    }


    while(1);
    // a = 10;
    // int *b = a.get<int>();
    // std::cout << *b << std::endl;
    // a = std::string("nihao");
    // std::string *str = a.get<std::string>();
    // std::cout << *str << std::endl;

    return 0;
}